package com.clw.classfile.attribute.info;

import com.clw.classfile.BytesReader;
import com.clw.classfile.attribute.Attribute;
import com.clw.classfile.constantpool.ConstantPool;

/**
 * Created by chengliwei on 2018/11/13.
 */
public class Code extends AttributeInfo {

    private short maxStack; // 操作数栈深度的最大值。虚拟机运行的时候根据这个值来分配栈
    private short maxLocals; // 局部变量表所需要的存储空间。单位是Slot，Slot是虚拟机为局部变量分配内存所使用的最小单位。
    // 对于byte/char/float/int/short/boolean/returnAddress等长度不超过32位的数据类型，每个局部变量占用1个Slot，而double和long这两种64位的数据类型则需要两个Slot
    private int codeLength; // 虚拟机规范限制一个方法不允许超过65535条字节码指令，所以实际上codeLength只使用了u2的长度（16位），超过这个限制，javac编译器会拒绝编译
    private byte[] code; // 编译后的字节码指令
    private short exceptionTableLength;
    private ExceptionInfo[] exceptionTable;
    private short attributeCount;
    private AttributeInfo[] attributes;

    private class ExceptionInfo {

        private short startPc;
        private short endPc;
        private short handlerPc;
        private short catchType;

        // 如果当字节码在第startPc行到第endPc行之间（不含endPc）出现了类型为catchType或者其
        // 子类的异常（catchType为指向一个CONSTANT_Class_info型变量的索引），则转到第handlerPc
        // 行继续处理
        // 注：这里“行”指的应该是偏移量


        public ExceptionInfo(short startPc, short endPc, short handlerPc, short catchType) {
            this.startPc = startPc;
            this.endPc = endPc;
            this.handlerPc = handlerPc;
            this.catchType = catchType;
        }
    }

    public Code(BytesReader bytesReader, ConstantPool constantPool) {
        super(bytesReader.readInt());
        byte[] bytes = bytesReader.readBytes(this.attributeLength);
        BytesReader reader = BytesReader.use(bytes);
        this.maxStack = reader.readShort();
        this.maxLocals = reader.readShort();
        this.codeLength = reader.readInt();
        this.code = reader.readBytes(codeLength);
        this.exceptionTableLength = reader.readShort();
        this.exceptionTable = new ExceptionInfo[exceptionTableLength];
        for (int i = 0; i < exceptionTableLength; i++) {
            exceptionTable[i] = new ExceptionInfo(reader.readShort(),
                    reader.readShort(), reader.readShort(), reader.readShort());
        }
        this.attributeCount = reader.readShort();
        this.attributes = new AttributeInfo[attributeCount];
        for (int i = 0; i < attributeCount; i++) {
            attributes[i] = Attribute.readAttribute(reader, constantPool);
        }
    }
}
